##########
#Imports #
##########
import es
import playerlib
import popuplib
import langlib
import gamethread
import services
import datetime
from sqlite3 import dbapi2 as sqlite
from configobj import ConfigObj

#####################
#Plugin Information #
#####################
info = es.AddonInfo()
info.name = 'ba_bank'
info.version = '2.5 BETA'
info.author = 'british.assassin'
info.url = 'http://addons.eventscripts.com/addons/view/ba_bank'
info.description = 'Allows players to store or withdraw their money from a virtual bank'
info.basename = 'ba_bank'
info.tags = 'cash'

##########
#Classes #
##########
class connection(object):
    def __init__(self,path):
        self.con = sqlite.connect(path)
        self.cur = self.con.cursor()
    def execute(self,sql):
        self.cur.execute(sql)
        self.con.commit()
    def query(self,sql):
        self.cur.execute(sql)
        return self.cur.fetchall()
    def close(self):
        self.con.close()

class account(object):
    def __init__(self,userid):
        self.player = playerlib.getPlayer(int(userid))
        self.deposits = 0
        self.withdrawals = 0
        self.transfers = 0
        (name,balance,autowithdraw) = db.query("SELECT name,balance,autowithdraw FROM accounts WHERE steamid='%s'" % self.player.get('steamid'))[0]
        self.balance = balance
        self.autowithdraw = autowithdraw
        self.date = datetime.date.today()
        db.execute("UPDATE accounts SET date='%s' WHERE steamid='%s'" %(datetime.date.today(),self.player.get('steamid')))
        if self.player.get('name') != name:
            db.execute("UPDATE accounts SET name='%s' WHERE steamid='%s'" %(player.get('name'),self.player.get('steamid')))
    def setbalance(self,amount):
        db.execute("UPDATE accounts SET balance='%d' WHERE steamid='%s';" % (amount,self.player.get('steamid')))
        self.balance = int(amount)
    def depositchecks(self):
        t = es.getplayercount(2)
        ct = es.getplayercount(3)
        if (t > 0) and (ct > 0):
            maxdeposits = int(config['settings']['bank_max_deposits'])
            if maxdeposits > 0:
                if self.deposits < maxdeposits:
                    return True
                else:
                    es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('max deposits',None,self.player.get("lang")))
                    return False
            else:
                return True
        else:
            es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('minimum players',None,self.player.get("lang")))
            return False
    def withdrawchecks(self):
        pistolround = int(config['settings']['bank_pistol_round'])
        maxwithdrawals = int(config['settings']['bank_max_withdrawals'])
        if maxwithdrawals > 0:
            if self.withdrawals < maxwithdrawals:
                if pistolround:
                    if roundno == 1:
                        es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('pistol round',None,self.player.get("lang")))
                        return False
                    else:
                        return True
                else:
                    return True
            else:
                es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('max withdrawals',None,self.player.get("lang")))
                return False
        else:
            if pistolround:
                if roundno == 1:
                    es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('pistol round',None,self.player.get("lang")))
                    return False
                else:
                    return True
            else:
                return True
    def transferchecks(self):
        maxtransfers = int(config['settings']['bank_max_transfers'])
        if maxtransfers > 0:
            if self.transfers < maxtransfers:
                return True
            else:
                es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('max transfers',None,self.player.get("lang")))
                return False
        else:
            return True
    def deposit(self,amount):
        if amount == "all":
            amount = int(self.player.get('cash'))
        else:
            amount = int(amount)
        mindeposit = int(config['settings']['bank_min_deposit'])
        if amount >= mindeposit:
            check = self.depositchecks()
            if check:
                cash = int(self.player.get('cash'))
                if cash >= amount:
                    maxbalance = int(config['settings']['bank_max_balance'])
                    if maxbalance > 0:
                        test = self.balance + amount
                        if test > maxbalance:
                            amount -= (test - maxbalance)
                    self.setbalance(self.balance + amount)
                    self.player.set('cash', cash - amount)
                    self.deposits += 1
                    tokens = {'amount':str(amount)}
                    es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('deposit',tokens,self.player.get("lang")))
                    es.event('initialize','bank_deposit')
                    es.event('setint','bank_deposit','userid',self.player.userid)
                    es.event('setint','bank_deposit','amount',amount)
                    es.event('fire','bank_deposit')
                else:
                    tokens = {'amount':str(amount)}
                    es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('no deposit',tokens,self.player.get("lang")))
        else:
            tokens = {'amount':str(amount)}
            es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('minimum deposit',tokens,self.player.get("lang")))
    def withdraw(self,amount):
        if amount == "fill":
            amount = 16000 - int(self.player.get('cash'))
        else:
            amount = int(amount)
        if amount > 0:
            check = self.withdrawchecks()
            if check:
                cash = int(self.player.get('cash'))
                test = cash + amount
                if test > 16000:
                    amount -= (test - 16000)
                if self.balance >= amount:
                    self.setbalance(self.balance - amount)
                    self.player.set('cash', cash + amount)
                    self.withdrawals += 1
                    tokens = {'amount':str(amount)}
                    es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('withdraw',tokens,self.player.get("lang")))
                    es.event('initialize','bank_withdraw')
                    es.event('setint','bank_withdraw','userid',self.player.userid)
                    es.event('setint','bank_withdraw','amount',amount)
                    es.event('fire','bank_withdraw')
                else:
                    tokens = {'amount':str(amount)}
                    es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('no withdraw',tokens,self.player.get("lang")))
    def transfer(self,receiver,amount):
        if amount == "all":
            amount = int(self.balance)
        else:
            amount = int(amount)
        if amount > 0:
            check = self.transferchecks()
            if check:
                try:
                    receiver = int(receiver)
                except:
                    es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('no userid',tokens,self.player.get("lang")))
                else:
                    if es.getplayersteamid(receiver) in accounts:
                        receiver = accounts[es.getplayersteamid(receiver)]
                        if amount <= self.balance:
                            maxbalance = int(config['settings']['bank_max_balance'])
                            if maxbalance > 0:
                                test = receiver.balance + amount
                                if test > maxbalance:
                                    amount -= (test - maxbalance)
                                self.setbalance(self.balance - amount)
                                receiver.setbalance(receiver.balance + amount)
                                self.transfers += 1
                                tokens = {'amount':amount,'player':receiver.player.get('name')}
                                es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('transfer',tokens,receiver.player.get("lang")))
                                tokens = {'amount':amount,'player':self.player.get('name')}
                                es.tell(receiver.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('transfer received',tokens,self.player.get("lang")))
                                es.event('initialize','bank_transfer')
                                es.event('setint','bank_transfer','userid',self.player.userid)
                                es.event('setint','bank_transfer','receiver',receiver.player.userid)
                                es.event('setint','bank_transfer','amount',amount)
                                es.event('fire','bank_transfer')
                        else:
                            tokens = {'amount':str(amount)}
                            es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('no transfer',tokens,self.player.get("lang")))
                    else:
                        es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('no account',None,self.player.get("lang")))
    def interest(self):
        interestrate = float(config['settings']['bank_interest_rate'])
        amount = int((self.balance/100)*interestrate)
        maxbalance = int(config['settings']['bank_max_balance'])
        if maxbalance > 0:
            test = self.balance + amount
            if test > maxbalance:
                amount -= (test - maxbalance)
        if amount > 0:
            self.setbalance(self.balance + amount)
            interest.append(self.player.userid)
            tokens = {'amount':str(amount)}
            es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('interest',tokens,self.player.get("lang")))
    def setautowithdraw(self,set):
        allowautowithdraw = int(config['settings']['bank_allow_autowithdrawal'])
        if allowautowithdraw:
            if set:
                db.execute("UPDATE accounts SET autowithdraw='1' WHERE steamid='%s';" %self.player.get('steamid'))
                self.autowithdraw = 1
                es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('autowithdraw on',None,self.player.get("lang")))
            else:
                db.execute("UPDATE accounts SET autowithdraw='0' WHERE steamid='%s';" %self.player.get('steamid'))
                self.autowithdraw = 0
                es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('autowithdraw off',None,self.player.get("lang")))
        else:
            es.tell(self.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('autowithdraw disabled',None,self.player.get("lang")))

##########
#Globals #
##########
db = connection(es.getAddonPath('ba_bank') + '/data/ba_bank.db')
config = ConfigObj(es.getAddonPath('ba_bank') + '/config/config.ini')
langs = langlib.Strings(es.getAddonPath("ba_bank") + "/config/langs.ini")
auth = services.use('auth')
accounts = {}
interest = []
transaction = {}
bank_disable = 0
roundno = 0

###################
#Custom Functions #
###################
def find(userid):
    steamid = es.getplayersteamid(userid)
    if steamid in accounts:
        return accounts[steamid]
    else:
        return None

def checkaccount(steamid):
    check = db.query("SELECT * FROM accounts WHERE steamid='%s'" % steamid)
    if check:
        return True
    else:
        return False

def createaccount(userid):
    player = playerlib.getPlayer(int(userid))
    startbalance = int(config['settings']['bank_start_balance'])
    db.execute("INSERT INTO accounts VALUES('%s','%s','%d','0','%s');" % (player.get('steamid'),player.get('name'),startbalance,datetime.date.today()))
    accounts[player.get('steamid')] = account(userid)
    es.tell(player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('account created',None,player.get("lang")))

def clear_inactive():
    inactiveDays = int(config['settings']['bank_inactive_days'])
    date = datetime.date.today() - datetime.timedelta(inactiveDays)
    db.execute("DELETE FROM accounts WHERE date<'%s'" %date)

def check_buyzone():
    global bank_disable
    entitylist = es.createentitylist('func_buyzone')
    if len(entitylist) > 0:
        bank_disable = False
    else:
        bank_disable = True

def bank_cmd():
    global bank_disable
    userid = es.getcmduserid()
    if auth.isUseridAuthorized(userid, "bank_use"):
        if not bank_disable:
            account = find(userid)
            if not account:
                createaccount(userid)
            player = playerlib.getPlayer(int(userid))
            try:
                args = es.getargs().split()
            except AttributeError:
                popuplib.send('bank_main',userid)
            else:
                if args[0] == 'deposit':
                    if len(args) == 2:
                        account.deposit(args[1])
                    else:
                        es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen Syntax: !bank deposit <amount>')
                elif args[0] == 'withdraw':
                    if len(args) == 2:
                        account.withdraw(args[1])
                    else:
                        es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen Syntax: !bank withdraw <amount>')
                elif args[0] == 'transfer':
                    if len(args) == 3:
                        account.transfer(args[1],args[2])
                    else:
                        es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen Syntax: !bank transfer <userid> <amount>')
                elif args[0] == 'admin':
                    if len(args) == 1:
                        if auth.isUseridAuthorized(userid, "bank_admin"):
                            popuplib.send('bank_admin',userid)
                        else:
                            es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('not admin',None,player.get("lang")))
                    else:
                        es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen Syntax: !bank admin')
                else:
                    es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('unknown command',None,player.get("lang")))
        else:
            es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('bank disabled',None,player.get("lang")))

#################
#Menu Functions #
#################
def makemenus():
    main = popuplib.create("bank_main")
    main.cachemode = 'user'
    main.addline(popuplib.langstring(config['settings']['bank_name'] + ' ', langs['main menu']))
    main.addlineAll("------------------------------")
    main.addline(popuplib.langstring('->1. ', langs['menu deposit']))
    main.addline(popuplib.langstring('->2. ', langs['menu withdraw']))
    main.addline(popuplib.langstring('->3. ', langs['menu transfer']))
    main.addline(popuplib.langstring('->4. ', langs['menu balance']))
    main.addline(popuplib.langstring('->5. ', langs['menu settings']))
    main.addline(popuplib.langstring('->6. ', langs['menu top']))
    main.addlineAll("------------------------------")
    main.addline(popuplib.langstring('0. ', langs['menu exit']))
    main.submenu(1,"bank_deposit")
    main.submenu(2,"bank_withdraw")
    main.submenu(3,"bank_transfer")
    main.select(4,query_balance)
    main.submenu(5,"bank_settings")
    main.submenu(6,"bank_top10")
    
    settings = popuplib.create("bank_settings")
    settings.cachemode = 'user'
    settings.addline(popuplib.langstring(config['settings']['bank_name'] + ' ', langs['settings menu']))
    settings.addlineAll("------------------------------")
    settings.addline(popuplib.langstring('->1. ', langs['menu autowithdraw']))
    settings.addlineAll("------------------------------")
    settings.addline(popuplib.langstring('0. ', langs['menu exit']))
    settings.prepuser = settings_prep
    settings.menuselect = settings_choice
    
    counter = 1
    top = popuplib.create("bank_top10")
    top.cachemode = 'user'
    top.addline(popuplib.langstring(config['settings']['bank_name'] + ' ', langs['top menu']))
    top.addlineAll("------------------------------")
    query = db.query("SELECT name,balance FROM accounts ORDER BY balance DESC LIMIT 10;")
    for name,balance in query:
        top.addlineAll("->%d. %s - $%d" % (counter,name,balance))
        counter += 1
    top.addlineAll("------------------------------")
    top.addline(popuplib.langstring('0. ', langs['menu exit']))
    top.prepuser = top10
    
    admin = popuplib.create("bank_admin")
    admin.cachemode = 'user'
    admin.addline(popuplib.langstring(config['settings']['bank_name'] + ' ', langs['admin menu']))
    admin.addlineAll("------------------------------")
    admin.addline(popuplib.langstring('->1. ', langs['menu cash']))
    admin.addline(popuplib.langstring('->2. ', langs['menu clear']))
    admin.addlineAll("------------------------------")
    admin.addline(popuplib.langstring('0. ', langs['menu exit']))
    admin.menuselect = admin_choice
    
    for menu in config['menus']:
        easymenu = popuplib.easymenu("bank_" + menu,None,bank_menus)
        easymenu.settitle(popuplib.langstring(config['settings']['bank_name'] + ' ', langs[menu + ' menu']))
        if menu == 'deposit':
            easymenu.addoption("all",langs['menu all'])
        elif menu == 'withdraw':
            easymenu.addoption("fill",langs['menu fill'])
        elif menu == 'transfer':
            easymenu.addoption("all",langs['menu entire'])
        menulist = []
        for menuitem in config['menus'][menu]:
            menulist.append([int(config['menus'][menu][menuitem]),menuitem])
        menulist.sort()
        for menuitem in menulist:
            easymenu.addoption(int(menuitem[0]), menuitem[1])
    
    players = popuplib.construct("bank_players","players","#human")
    players.menuselectfb = players_choice
    players.settitle(popuplib.langstring(config['settings']['bank_name'] + ' ', langs['players menu']))

def settings_prep(userid, popupid):
    settings = popuplib.find("bank_settings")
    allowautowithdraw = config['settings']['bank_allow_autowithdrawal']
    if allowautowithdraw:
        account = find(userid)
        autowithdraw = account.autowithdraw
        if autowithdraw:
            settings.modline(3,popuplib.langstring('->1. ', langs['menu autowithdraw on']))
        else:
            settings.modline(3,popuplib.langstring('->1. ', langs['menu autowithdraw off']))
    else:
        settings.modline(3,popuplib.langstring('->1. ', langs['menu autowithdraw disabled']))
    settings.recache([userid])

def top10(userid, popupid):
    top = popuplib.find("bank_top10")
    counter = 3
    query = db.query("SELECT name,balance FROM accounts ORDER BY balance DESC LIMIT 10;")
    for name,balance in query:
        string = "->%d. %s - $%d" % (counter-2,name,balance)
        top.modlineAll(int(counter),string)
        counter += 1
    top.recache([userid])

def query_balance(userid, choice, popupid):
    account = find(userid)
    tokens = {'amount':account.balance}
    es.tell(account.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('balance',tokens,account.player.get("lang")))

def settings_choice(userid, choice, popupid):
    if choice == 1:
        account = find(userid)
        autowithdraw = account.autowithdraw
        if autowithdraw:
            account.setautowithdraw(False)
        else:
            account.setautowithdraw(True)

def admin_choice(userid, choice, popupid):
    player = playerlib.getPlayer(int(userid))
    if choice == 1:
        if auth.isUseridAuthorized(userid, "bank_cash"):
            popuplib.send('bank_admincash',userid)
        else:
            es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('not authorised',None,player.get("lang")))
    elif choice == 2:
        if auth.isUseridAuthorized(userid, "bank_clear"):
            clear_inactive()
            es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('inactive deleted',None,player.get("lang")))
        else:
            es.tell(userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('not authorised',None,player.get("lang")))        

def bank_menus(userid, choice, popupid):
    account = find(userid)
    if popupid == "bank_deposit":
        account.deposit(choice)
    elif popupid == "bank_withdraw":
        account.withdraw(choice)
    elif popupid == "bank_transfer":
        transaction[userid] = ['transfer',choice]
        popuplib.send("bank_players",userid)
    elif popupid == "bank_admincash":
        transaction[userid] = ['admincash',choice]
        popuplib.send("bank_players",userid)

def players_choice(userid, choice, popupid):
    if transaction[userid][0] == 'transfer':
        account = find(userid)
        account.transfer(choice,transaction[userid][1])
    elif transaction[userid][0] == 'admincash':
        account = find(choice)
        if account:
            account.setbalance(account.balance + int(transaction[userid][1]))
            tokens = {'amount':transaction[userid][1]}
            es.tell(account.player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('admin give',tokens,account.player.get("lang")))
            es.event('initialize','bank_admin_cash')
            es.event('setint','bank_admin_cash','userid',userid)
            es.event('setint','bank_admin_cash','receiver',choice)
            es.event('setint','bank_admin_cash','amount',transaction[userid][1])
            es.event('fire','bank_admin_cash')
        else:
            player = playerlib.getPlayer(userid)
            es.tell(player.userid,'#multi', '#green' + config['settings']['bank_name'] + '#lightgreen ' + langs('no account',None,player.get("lang")))
    del transaction[userid]

#########
#Events #
#########
def load():
    bank_ver = es.ServerVar('ba_bank_version',info.version,'[BA_BANK] version')
    bank_ver.makepublic()
    db.execute('CREATE TABLE IF NOT EXISTS accounts (steamid VARCHAR(20) UNIQUE NOT NULL,name VARCHAR(40) NOT NULL,balance INTEGER NOT NULL,autowithdraw BOOLEAN NOT NULL,date DATE NOT NULL)')
    auth.registerCapability('bank_use',auth.IDENTIFIED)
    auth.registerCapability('bank_admin',auth.ADMIN)
    auth.registerCapability('bank_cash',auth.ADMIN)
    auth.registerCapability('bank_clear',auth.ADMIN)
    if not es.exists("saycommand", "!bank"):
        es.regsaycmd('!bank',"ba_bank/bank_cmd",'[BA_BANK] Basic bank command')
    if not es.exists("clientcommand", "!bank"):
        es.regclientcmd('!bank',"ba_bank/bank_cmd",'[BA_BANK] Basic bank command')
    makemenus()
    es.loadevents("declare", "addons/eventscripts/ba_bank/data/ba_bank.res")

def unload():
    es.unregsaycmd('!bank')
    es.unregclientcmd('!bank')
    db.close()

def es_map_start(event_var):
    global roundno
    roundno = 1
    allowinterest = int(config['settings']['bank_interest_allow'])
    if allowinterest:
        interest = []
    clearInactive = int(config['settings']['bank_auto_clear_inactive'])
    if clearInactive:
        clear_inactive()
    buyzoneDisable = int(config['settings']['bank_buyzone_disable'])
    if buyzoneDisable:
        gamethread.delayed(5,check_buyzone)
    es.loadevents("addons/eventscripts/ba_bank/data/ba_bank.res")

def player_activate(event_var):
    if checkaccount(event_var['es_steamid']):
        accounts[event_var['es_steamid']] = account(event_var['userid'])

def player_disconnect(event_var):
    if event_var['networkid'] in accounts:
        del accounts[event_var['networkid']]

def round_end(event_var):
    global roundno
    if event_var['reason'] == 16:
        roundno = 1
    else:
        roundno += 1
    allowinterest = int(config['settings']['bank_interest_allow'])
    if allowinterest:
        perround = int(config['settings']['bank_interest_per_round'])
        if perround:
            interest = []

def player_spawn(event_var):
    if event_var['es_userteam'] > 1:
        if event_var['es_steamid'] in accounts:
            account = accounts[event_var['es_steamid']]
            account.deposits,account.withdrawals,account.transfers = 0,0,0
            allowinterest = int(config['settings']['bank_interest_allow'])
            if allowinterest:
                if not event_var['userid'] in interest:
                    account.interest()
            if account.autowithdraw:
                account.withdraw('fill')
